package webreg.model;

import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;

import webreg.model.exceptions.EmptyDescriptionException;
import webreg.model.exceptions.EmptyLabelException;


/**
 * This is the implementation of a disciplin class for athletics.
 *  
 * @author STKNOLL
 */
@XmlAccessorType(XmlAccessType.NONE)
public class Disciplin implements Cloneable{

	@XmlAttribute (name = "label")
	private String mLabel;
	@XmlAttribute (name = "description")
	private String mDescription;
	@XmlAttribute (name = "price")
	private double mPrice;
	@XmlElement (name = "PersonalBest")
	private BestPerformance mPersonalBest;

	/** Contructor for a disciplin 
	 */
	public Disciplin() {
		this.mLabel = "";
		this.mDescription = "";
		this.mPrice = 0.00;
		this.mPersonalBest = null;
	}

	/** Contructor for a disciplin with attributes
	 * 
	 * @param label The short text of the disciplin
	 * @param description The long form of the disciplin
	 * @throws EmptyLabelException 
	 * @throws EmptyDescriptionException 
	 */
	public Disciplin(String label, String description) throws EmptyLabelException, EmptyDescriptionException {
		this();
		setLabel(label);
		setDescription(description);
	}

	/** Contructor for a disciplin with attributes
	 *  
	 * @param label The short text for a disciplin
	 * @param description A long description for the disciplin
	 * @param price The price of a disciplin
	 * @throws EmptyDescriptionException 
	 * @throws EmptyLabelException 
	 */
	public Disciplin(String label, String description, double price) throws EmptyLabelException, EmptyDescriptionException {
		this(label, description);
		setPrice(price);
	}

	/** Contructor for a disciplin with attributes
	 *  
	 * @param label The short text for a disciplin
	 * @param description A long description for the disciplin
	 * @param price The price of a disciplin as string
	 * @throws EmptyDescriptionException 
	 * @throws EmptyLabelException 
	 */
	public Disciplin(String label, String description, String price) throws EmptyLabelException, EmptyDescriptionException {
		this(label, description);
		setPrice(price);
	}

	/** Contructor for a disciplin with attributes
	 *
	 * @param label The short text for a disciplin
	 * @param description A long description for the disciplin
	 * @param price The price of a disciplin
	 * @param pb The best performance for this disciplin
	 * @throws EmptyDescriptionException 
	 * @throws EmptyLabelException 
	 */
	public Disciplin(String label, String description, double price, BestPerformance pb) throws EmptyLabelException, EmptyDescriptionException {
		this(label, description, price);
		setPersonalBest(pb);
	}

	/** Contructor for a disciplin with attributes
	 *
	 * @param label The short text for a disciplin
	 * @param description A long description for the disciplin
	 * @param price The price of a disciplin as string
	 * @param pb The best performance for this disciplin
	 * @throws EmptyDescriptionException 
	 * @throws EmptyLabelException 
	 */
	public Disciplin(String label, String description, String price, BestPerformance pb) throws EmptyLabelException, EmptyDescriptionException {
		this(label, description, price);
		setPersonalBest(pb);
	}
	
	/**
	 * Creates a disciplin based on an already existing one
	 * @param cDis The disciplin to copy
	 * @throws EmptyDescriptionException 
	 * @throws EmptyLabelException 
	 */
	public Disciplin(Disciplin toCopy) {
		this( );
		mLabel = toCopy.mLabel;
		mDescription = toCopy.mDescription;
		mPrice = toCopy.mPrice;
		mPersonalBest = toCopy.mPersonalBest;
	}
	
	
	/** Implementation of the equal function for this class
	 * 
	 * @param toCompare The value to compare
	 * @see java.lang.Object#equals(java.lang.Object)
	 */
	public boolean equals(Disciplin toCompare) {
		if ( this.mPrice != toCompare.mPrice ) return false;
		if ( this.mLabel.equals(toCompare.mLabel) == false ) return false;
		if ( this.mDescription.equals(toCompare.mDescription) == false ) return false;
		if ( ( mPersonalBest != null && toCompare.mPersonalBest != null ) && 
			 ( this.mPersonalBest.equals(toCompare.mPersonalBest) == false ) 
			) return false;
		return true;
	}

	/** 
	 * Returns the mDescription of the disciplin
	 * @return Description of the disciplin
	 */
	public String getDescription() {
		return mDescription;
	}

	/**
	 * Set the mDescription of the disciplin
	 * @param mDescription The decription of the disciplin
	 * @throws EmptyDescriptionException 
	 */
	public void setDescription(String description) throws EmptyDescriptionException {
		if ((description == null) || (description.trim().equals(""))) throw new EmptyDescriptionException( "Disciplin " + getLabel() );
		this.mDescription = description;
	}

	/**
	 * Returns the mLabel of the discipliin
	 * @return Label of the disciplin
	 */
	public String getLabel() {
		return mLabel;
	}

	/**
	 * Will set the mLabel of the disciplin
	 * @param mLabel The new mLabel text
	 * @throws EmptyLabelException 
	 */
	public void setLabel(String label) throws EmptyLabelException {
		if ((label == null) || (label.trim().equals(""))) throw new EmptyLabelException( "Disciplin " + getDescription() );
		this.mLabel = label;
	}

	/**
	 * Returns the mPrice for this disciplin
	 * @return The mPrice
	 */
	public double getPrice() {
		return mPrice;
	}

	/**
	 * Returns the mPrice for this disciplin as string
	 * @return The mPrice
	 */
	public String getPriceAsString() {
		return new Double(mPrice).toString();
	}

	/**
	 * Sets the mPrice of the disciplin to a given value
	 * @param mPrice The mPrice to set
	 */
	public void setPrice(double price) {
		this.mPrice = price;
	}

	/**
	 * Sets the mPrice of the disciplin to a given value.
	 * @param mPrice The mPrice to set, must be not ""
	 */
	public void setPrice(String price) {
		if ( price.trim().equals("") == false ) {
			this.mPrice = new Double(price).doubleValue();
		}
	}

	/**
	 * Returns the personal best for that disciplin 
	 * 
	 * @return The personal best for this disciplin
	 */
	public BestPerformance getPersonalBest() {
		return mPersonalBest;
	}
	
	/**
	 * Sets the personal best for that disciplin to the given value
	 * 
	 * @param pb The personal best to set
	 */
	public void setPersonalBest(BestPerformance pb) {
		this.mPersonalBest = pb;
	}

	@Override
	public String toString() {
		return getLabel();
	}

	@Override
	public Object clone(){	
		Disciplin newDisciplin = new Disciplin();
		newDisciplin.mLabel = mLabel;
		newDisciplin.mDescription = mDescription;
		newDisciplin.mPrice = mPrice;
		newDisciplin.mPersonalBest = (BestPerformance)mPersonalBest.clone();
		return newDisciplin;
	}
	
	public int compareTo(Disciplin other) {
		int labelCompare = mLabel.compareTo( other.mLabel );
		if (labelCompare != 0) { return labelCompare; }
		
		int descriptionCompare = mDescription.compareTo(other.mDescription);
		if (descriptionCompare != 0) { return descriptionCompare; }

		if ( mPrice < other.mPrice) { return -1; }
		else if ( mPrice > other.mPrice) { return 1; }

		if ( (mPersonalBest != null) && (other.mPersonalBest != null) ) {
			int bestPerfCompare = mPersonalBest.compareTo( other.mPersonalBest );
			if (bestPerfCompare != 0) { return bestPerfCompare; }
		}
		return 0;
	}
	
}
